#pragma once
#include "util.hpp"
#include "Lock.hpp"

int gThreadNum = 5;
template<typename T>
class ThreadPool
{
private:
    ThreadPool(int threadNum = gThreadNum)
        :_threadNum(threadNum), _isStart(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool<T>&) = delete ;
    void operator=(const ThreadPool<T>&) = delete ;
public:
    static ThreadPool<T>* getInstance(int threadNum = gThreadNum)
    {
        //防止申请多把锁
        static Mutex mutex;
        if (nullptr == instance)
        {
            LockGuard Lock(&mutex);
            if (nullptr == instance)
            {
                instance = new ThreadPool<T>(threadNum);
            }
        }
        return instance;
    }

    //用static去除this指针, 将this指针以参数传给函数
    static void* threadRoutine(void* args)
    {
        pthread_detach(pthread_self());
        ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);
        while (true)
        {
            T task = tp->pop();
            task();
        }
    }

    T pop()
    {
        lockQueue(); 
        while (empty())
        {
            waitForTask();
        }
        T t = _q.front();
        _q.pop(); 
        unlockQueue();
        return t;
    }

    void start()
    {
        if (_isStart)
        {
            return;
        }
        for (int i = 0; i < _threadNum; ++i)
        {
            pthread_t tmp;
            pthread_create(&tmp, nullptr, threadRoutine, this);
        }
        _isStart = true;
    }

    void push(const T& in)
    {
        lockQueue();
        _q.push(in);
        DoTask();
        unlockQueue();
    }
    ~ThreadPool<T>()
    {
        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mutex);
    }

    int threadNum()
    {
        return _threadNum;
    }
private:
    bool empty()
    {
        return _q.empty();
    }
    void DoTask()
    {
        pthread_cond_signal(&_cond);
    }
    void waitForTask()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void lockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

private:

    bool _isStart;
    int _threadNum;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    queue<T> _q;
    static ThreadPool<T>* instance; 
};

template<typename T>
ThreadPool<T>* ThreadPool<T>::instance = nullptr;
